package ru.passivemoney.common;

import static ru.passivemoney.common.Consts.DIFF_BEFORE_GO_TO_ZERRO;

import java.math.BigDecimal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.passivemoney.manage.job.Job;
import ru.passivemoney.manage.job.JobSL;
import ru.passivemoney.manage.job.JobsRunner;
import ru.passivemoney.root.ContextHolder;

import com.dukascopy.api.IBar;
import com.dukascopy.api.IOrder;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.OfferSide;
import com.dukascopy.api.Period;

public class UtilsOrders {
	private static final Logger logger = LoggerFactory.getLogger(UtilsOrders.class);
	
	private static final String LOG_ORDER_MANAGE = "ORDER_MANAGE";
	
	public static enum ActionUnderOrder{
		CHANGE,
		CLOSE,
		SUBMIT;
	}
	
	public static String keyForSharedMap(IOrder order, ActionUnderOrder action){
    	return order.getLabel() + "_" + order.getId() + "_" + action;
    	
    }
	
	/**
	 * 
	 * @param order
	 * @param askPrice
	 * @param bidPrice
	 * @return <b>true</b> - если данный ордер должен быть удалён из списка открытых ордеров, т.к. отправляется на модификацию;<br/>
	 * <b>flase</b> - ордер не должен быть удалён из списка открытых ордеров
	 */
	public static boolean putOrderToModificationJobs(IOrder order, double askPrice, double bidPrice){
		Job job = null;
		
		if(order.isLong()){
			job = openedBullOrderManage(order, askPrice, bidPrice);
		}else{
			job = openedBearOrderManage(order, askPrice, bidPrice);
		}
		
		if(job != null){
			JobsRunner.putJob(job);
			return true;
		}else{
			return false;
		}
	}
	
	public static Job openedBullOrderManage(IOrder order, double askPrice, double bidPrice) {
		// Уходим в ноль
		Job jobSl = null;
		if (order.getStopLossPrice() < order.getOpenPrice() && bidPrice - order.getOpenPrice() >= DIFF_BEFORE_GO_TO_ZERRO * order.getInstrument().getPipValue()) {
			logger.info("{} - Move bull order '{}' to zerro", LOG_ORDER_MANAGE, order.getLabel());
			logOrderDataBeforeModification(order, askPrice, bidPrice);
			jobSl = new JobSL(order, new BigDecimal(order.getOpenPrice() + Consts.ADDITION_BEFORE_GO_TO_ZERO), Consts.SLIPPAGE);
		}

		// поднимаем SL
		if (order.getStopLossPrice() >= order.getOpenPrice() && bidPrice - order.getStopLossPrice() > order.getInstrument().getPipValue() * Consts.TS) {
			logger.info("{} - UP stop loss for order {}", LOG_ORDER_MANAGE, order.getLabel());
			logOrderDataBeforeModification(order, askPrice, bidPrice);
			jobSl = new JobSL(order, new BigDecimal(bidPrice - order.getInstrument().getPipValue() * Consts.TS), Consts.SLIPPAGE);
		}
		
		return jobSl;
	}
	
	public static Job openedBearOrderManage(IOrder order, double askPrice, double bidPrice) {
		// Уходим в ноль
		Job jobSl = null;
		if (order.getStopLossPrice() > order.getOpenPrice() && order.getOpenPrice() - askPrice > DIFF_BEFORE_GO_TO_ZERRO * order.getInstrument().getPipValue()) {
			logger.info("{} - Move bear order '{}' to zerro", LOG_ORDER_MANAGE, order.getLabel());
			logOrderDataBeforeModification(order, askPrice, bidPrice);
			jobSl = new JobSL(order, new BigDecimal(order.getOpenPrice() - Consts.ADDITION_BEFORE_GO_TO_ZERO), Consts.SLIPPAGE);
		}

		// опускаем SL
		if (order.getStopLossPrice() < order.getOpenPrice() && order.getStopLossPrice() - askPrice > order.getInstrument().getPipValue() * Consts.TS) {
			logger.info("{} - DOWN stop loss for order {}", LOG_ORDER_MANAGE, order.getLabel());
			logOrderDataBeforeModification(order, askPrice, bidPrice);
			jobSl = new JobSL(order, new BigDecimal(askPrice + order.getInstrument().getPipValue() * Consts.TS), Consts.SLIPPAGE);
		}
		
		return jobSl;
	}
	
	private static void logOrderDataBeforeModification(IOrder order, double askPrice, double bidPrice) {
		logger.info("OrderStopLoss = " + order.getStopLossPrice());
		logger.info("OrderOpenPrice = " + order.getOpenPrice());
		logger.info("Bid = " + bidPrice);
		logger.info("Ask = " + askPrice);
	}
    
    public static boolean isOrderOpenedOrFilled(IOrder order){
    	return order.getState().equals(IOrder.State.FILLED) || order.getState().equals(IOrder.State.CREATED);
    }
    
    public static IBar getPreviousBar(Instrument instrument, Period period, OfferSide offerSide){
    	return getBar(instrument, period, offerSide, 1);
    }
    
    public static IBar getBar(Instrument instrument, Period period, OfferSide offerSide, int shift){
    	try {
			return ContextHolder.getContext().getHistory().getBar(instrument, period, offerSide, shift);
		} catch (JFException e) {
			logger.error("Error when getting previous bar", e);
		}
    	return null;
    }
    
}
